package com.chu.cloud.service;

import com.chu.cloud.dto.ProductPointPlanDto;
import com.chu.cloud.dto.order.OrderItemDto;
import com.chu.cloud.entity.Product;
import com.chu.cloud.entity.ProductPointPlan;
import com.chu.cloud.enums.RedisKeyPrefix;
import com.chu.cloud.repository.ProductPointPlanRepository;
import com.chu.cloud.repository.ProductRepository;
import com.chu.cloud.stream.payload.OrderProductReturnDto;
import com.chu.cloud.util.BeanUtil;
import com.chu.cloud.util.ChuException;
import com.chu.cloud.util.JsonUtils;
import com.chu.cloud.util.RedisUtil;
import com.chu.cloud.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description:
 * @author: TianShu.CHU
 * @CreateDate: 2018-05-14 23:43
 * @Version: 1.0
 */
@Service
@Slf4j
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private ProductPointPlanRepository pointPlanRepository;

    @Transactional(rollbackFor = Exception.class)
    public List<ProductPointPlanDto> reserveProducts(List<OrderItemDto> itemList) {
        List<Integer> productIds = itemList.stream().map(OrderItemDto::getProductId).collect(Collectors.toList());
        List<Product> products = productRepository.findByIdIn(productIds.toArray(new Integer[productIds.size()]));

        Map<Integer, Product> productMap = products.stream().
                collect(Collectors.toMap(Product::getId, product -> product));

        List<ProductPointPlanDto> result = new ArrayList<>();
        itemList.forEach(item -> {
            Integer productId = item.getProductId();
            Product product = productMap.get(productId);

            if (item.getQuantity() > product.getStocks()) {
                log.error("订单中此商品%s购买数量%s,库存不足", String.format(product.getProductName(), item.getQuantity()));
                throw new ChuException(String.format("商品%s,库存不足", product.getProductName()));
            }
            //冻结订单相应的商品数目
            product.setStocks(product.getStocks() - item.getQuantity());
            productRepository.save(product);
            ProductPointPlanDto pointPlanDto = new ProductPointPlanDto();
            pointPlanDto.setProductId(productId);
            pointPlanDto.setRewardPoint(0);
            pointPlanDto.setPrice(product.getPrice());
            pointPlanDto.setQuantity(item.getQuantity());

            //查看是否有该商品的积分返点设置,且在有效期
            Optional.ofNullable(pointPlanRepository.findByProductId(productId)).
                    filter(point -> point.getEndTime().compareTo(new Date()) > 0)
                    .ifPresent(pointPlan -> pointPlanDto.setRewardPoint(pointPlan.getPoint()));

            result.add(pointPlanDto);

        });
        log.info("预留订单商品成功:{}", JsonUtils.obj2json(result));

        return result;
    }

    public Boolean lockInventory(Integer productId, Integer quantity) {
        Product product = Optional.ofNullable(productRepository.findOne(productId))
                .orElseThrow(() -> new ChuException("商品不存在"));
        if (product.getStocks().compareTo(quantity) < 0) {
            return false;
        }
        product.setStocks(product.getStocks() - quantity);
        productRepository.save(product);
        return true;
    }

    public void returnProduct(List<OrderProductReturnDto> payLoad) {
        List<Integer> productIds = payLoad.stream().map(OrderProductReturnDto::getProductId).collect(Collectors.toList());
        List<Product> products = productRepository.findByIdIn(productIds.toArray(new Integer[productIds.size()]));
        Map<Integer, Product> productMap = products.stream().collect(Collectors.toMap(Product::getId, product -> product));
        payLoad.forEach(orderProduct -> {
            Product product = productMap.get(orderProduct.getProductId());
            product.setStocks(product.getStocks() + orderProduct.getQuantity());
        });
        productRepository.save(productMap.values());
    }


    public Integer save(Product product) {
        if (product.getId() != null) {
            RedisUtil.del(RedisKeyPrefix.PRODUCT_STOCKS, product.getId());
            RedisUtil.del(RedisKeyPrefix.PRODUCT_ID, product.getId());
        }
        Product save = productRepository.save(product);
        ProductVo productVo = new ProductVo();
        BeanUtil.copyProperties(productVo, product);
        RedisUtil.set(RedisKeyPrefix.PRODUCT_ID, productVo.getId(), productVo);
        RedisUtil.set(RedisKeyPrefix.PRODUCT_STOCKS, save.getId(), save.getStocks());
        return save.getId();
    }

    public void cleanerExpirePointProduct() {
        Date curDate = DateTime.now().toDate();
        List<ProductPointPlan> list = pointPlanRepository.findByEndTimeLessThan(curDate);
        pointPlanRepository.delete(list);
    }


}
